package org.andromda.cartridges.gwt.metafacades;

import java.util.Collection;
import java.util.Iterator;

import org.andromda.metafacades.uml.ClassifierFacade;
import org.andromda.metafacades.uml.DependencyFacade;
import org.andromda.metafacades.uml.MetafacadeUtils;
import org.andromda.metafacades.uml.ModelElementFacade;
import org.andromda.metafacades.uml.OperationFacade;
import org.andromda.metafacades.uml.Service;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

/**
 * MetafacadeLogic implementation for org.andromda.cartridges.gwt.metafacades.GwtAsyncService.
 * 
 * @see org.andromda.cartridges.gwt.metafacades.GwtServiceAsync
 */
public class GwtServiceLogicImpl extends GwtServiceLogic {

	/**
	 * The logger instance.
	 */
	private static final Logger	logger	= Logger.getLogger( GwtServiceLogicImpl.class );

	public GwtServiceLogicImpl(Object metaObject, String context) {
		super( metaObject, context );
	}

	@Override
	protected String handleGetImplementationCall(OperationFacade operation) {
		return this.getImplementationOperationName( StringUtils.capitalize( operation.getCall() ) );
	}

	private String getImplementationOperationName(String replacement) {
		return StringUtils.trimToEmpty(
		        String.valueOf( this.getConfiguredProperty( GwtGlobals.IMPLEMENTATION_OPERATION_NAME_PATTERN ) ) )
		        .replaceAll( "\\{0\\}", replacement );
	}

	public static String getSignature(final String name, Collection arguments, final boolean withArgumentNames) {
		final StringBuffer signature = new StringBuffer( name );
		signature.append( "(" );
		String argList = MetafacadeUtils.getTypedArgumentList( arguments, withArgumentNames, null );
		signature.append( argList );
		signature.append( ")" );
		return signature.toString();
	}

	public static String getAsyncSignature(final String name, Collection arguments, final boolean withArgumentNames,
	        ClassifierFacade returnType) {
		final StringBuffer signature = new StringBuffer( name );
		signature.append( "(" );
		String argList = MetafacadeUtils.getTypedArgumentList( arguments, withArgumentNames, null );
		signature.append( argList );
		String returnTypeStr = returnType.getFullyQualifiedName();
		if ( returnTypeStr.equalsIgnoreCase( "void" ) ) {
			returnTypeStr = "java.lang.Void";
		} else if ( returnTypeStr.equalsIgnoreCase( "boolean" ) ) {
			returnTypeStr = "java.lang.Boolean";
		} else if ( returnTypeStr.equalsIgnoreCase( "int" ) ) {
			returnTypeStr = "java.lang.Integer";
		}
		if ( argList.trim().length() > 0 ) {
			signature.append( ", " );
		}
		signature.append( "AsyncCallback<" + returnTypeStr + "> callback )" );
		return signature.toString();
	}

	/**
	 * @see org.andromda.cartridges.gwt.metafacades.GwtServiceAsync#getAsyncSignature()
	 */
	@Override
	protected String handleGetAsyncSignature(OperationFacade operation) {
		return getAsyncSignature( operation.getName(), operation.getArguments(), true, operation.getReturnType() );
	}

	@Override
	protected Object handleGetRelatedService() {
		if ( this.getSourceDependencies().size() > 0 ) {
			for ( Iterator i = this.getSourceDependencies().iterator(); i.hasNext(); ) {
				ModelElementFacade targetElement = ( ( DependencyFacade ) i.next() ).getTargetElement();
				if ( ( targetElement != null ) && Service.class.isAssignableFrom( targetElement.getClass() ) ) {
					Service s = ( Service ) targetElement;
					return s;
				}
			}
			logger.error( "Cannot find a related service for " + getName() );
		} else {
			logger.error( "There is no dependencies for " + getName() );
		}

		return null;
	}

	@Override
	protected Collection handleGetRelatedOperations() {
		Service relatedService = ( Service ) handleGetRelatedService();
		return relatedService.getOperations();
	}

	@Override
	protected String handleGetServiceFullyQualifiedName() {
		Service relatedService = ( Service ) handleGetRelatedService();
		return relatedService.getFullyQualifiedName();
	}

	@Override
	protected String handleGetSignature(OperationFacade operation) {
		return getSignature( operation.getName(), operation.getArguments(), true );
	}
}